

class OAuthStore:

	def setOAuthConsumerKeyAndSecret(self, providerKey, keyAndSecret):
		from lib import Util;
		Util.abstract();

	def setTokenAndSecret(self, tokenKey, tokenInfo):
		from lib import Util;
		Util.abstract();

	
	# Retrieve an OAuthAccessor that is ready to sign OAuthMessages for
	# resource access.
	# @param tokenKey a structure uniquely identifying the token: a userId,
	#                 a gadgetId, a moduleId (in case there are more than one
	#                 gadget of the same type on a page), a tokenName (which
	#                 distinguishes this token from others that the same gadget
	#                 might hold for the same service provider) and a serviceName
	#                 (which is the same as the service name in the ProviderKey
	#                 structure).
	# @param provInfo provider information. The store combines information stored
	#                 in the store (consumer key/secret, token, token secret,
	#                 etc.) with the provider information (access URL, request
	#                 URL etc.) passed in here to create an AccessorInfo object.
	#                 If no information can be found in the
	#                 store, it may use default keys that identify the container,
	#                 as opposed to consumer keys and secrets that are specific
	#                 to this gadget.
	# @return an OAuthAccessor object than can be passed to an OAuthMessage.sign
	#         method.
	
	def getOAuthAccessorTokenKey(self, tokenKey, provInfo):
		from lib import Util;
		Util.abstract();

	def getOAuthAccessorProviderKey(self, providerKey, provInfo):
		from lib import Util;
		Util.abstract();

class OAuthStoreVars:
	HttpMethod = {'GET' : 'GET', 'POST' : 'POST'};
	SignatureType = {'HMAC_SHA1' : 'HMAC_SHA1', 'RSA_SHA1' : 'RSA_SHA1', 
			'PLAINTEXT' : 'PLAINTEXT'};
	KeyType = {'HMAC_SYMMETRIC' : 'HMAC_SYMMETRIC', 
			'RSA_PRIVATE' : 'RSA_PRIVATE'};
	OAuthParamLocation = {'AUTH_HEADER' : 'auth_header', 
			'POST_BODY' : 'post_body', 'URI_QUERY' : 'uri_query'};

class AccesorInfo:
	def _init__(self):
		self.accessor;
		self.httpMethod;
		self.signatureType;
		self.paramLocation;

	def getParamLocation(self):
		return self.paramLocation;

	def setParamLocation(self, paramLocation):
		self.paramLocation = paramLocation;

	def getAccessor(self):
		return self.accessor;

	def setAccessor(self, accessor):
		self.accessor = accessor;

	def getHttpMethod(self):
		return self.httpMethod;

	def setHttpMethod(self, httpMethod):
		self.httpMethod = httpMethod;
	

	def getSignatureType(self):
		return self.signatureType;

	def setSignatureType(self, signatureType):
		self.signatureType = signatureType;
	

class ConsumerKeyAndSecret:
	
	def __init__(self, key, secret, type):
		self.__consumerKey_ = key;
		self.__consumerSecret_ = secret;
		self.__keyType_ = type;

	def getConsumerKey(self):
		return self.__consumerKey_;

	def getConsumerSecret(self):
		return self.__consumerSecret_;

	def getKeyType(self):
		return self.__keyType_;

class ProviderKey:
	def __init__(self):
		self.__gadgetUri_;
		self.__serviceName_;

	def getGadgetUri(self):
		return self.__gadgetUri_;

	def setGadgetUri(self, gadgetUri):
		self.__gadgetUri_ = gadgetUri;

	def getServiceName(self):
		return self.__serviceName_;

	def setServiceName(self, serviceName):
		self.__serviceName_ = serviceName;

class ProviderInfo:
	def __init__(self):
		self.__provider_;
		self.__httpMethod_;
		self.__signatureType_;
		self.__paramLocation_;
		
		# this can be None if we have not negotiated a consumer key and secret
		# yet with the provider, or if we decided that we want to use a global
		# public key
		self.__keyAndSecret_;

	def getParamLocation(self):
		return self.__paramLocation_;

	def setParamLocation(self, paramLocation):
		self.__paramLocation_ = paramLocation;

	def getKeyAndSecret(self):
		return self.__keyAndSecret_;

	def setKeyAndSecret(self, keyAndSecret):
		self.__keyAndSecret_ = keyAndSecret;

	def getProvider(self):
		return self.__provider_;

	def setProvider(self, provider):
		self.__provider_ = provider;

	def getHttpMethod(self):
		return self.__httpMethod_;

	def setHttpMethod(self, httpMethod):
		self.__httpMethod_ = httpMethod;

	def getSignatureType(self):
		return self.__signatureType_;

	def setSignatureType(self, signatureType):
		self.__signatureType_ = signatureType;


class TokenKey:
	def __init__(self):
		self.__userId_;
		self.__gadgetUri_;
		self.__moduleId_;
		self.__tokenName_;
		self.__serviceName_;

	def getUserId(self):
		return self.__userId_;

	def setUserId(self, userId):
		self.__userId_ = userId;

	def getGadgetUri(self):
		return self.__gadgetUri_;

	def setGadgetUri(self, gadgetUri):
		self.__gadgetUri_ = gadgetUri;

	def getModuleId(self):
		return self.__moduleId_;

	def setModuleId(self, moduleId):
		self.__moduleId_ = moduleId;

	def getTokenName(self):
		return self.__tokenName_;

	def setTokenName(self, tokenName):
		self.__tokenName_ = tokenName;

	def getServiceName(self):
		return self.__serviceName_;

	def setServiceName(self, serviceName):
		self.__serviceName_ = serviceName;

class TokenInfo:
	
	def __init__(self, token, secret):
		self.__accessToken_ = token;
		self.__tokenSecret_ = secret;

	def getAccessToken(self):
		return self.accessToken;

	def getTokenSecret(self):
		return self.tokenSecret;


# The OAuth preferences located in the gadget xml inside ModulePrefs.
# Now, it only has 1 property, but this class was designed to be reusable
class OAuthSpec:

	def __init__(self, services):
		self.__oAuthServices_ = {};
		for service in services:
			oauthService = OAuthService(service);
			self.__oAuthServices_[oauthService.getName()] = oauthService;

	def getServices(self):
		return self.oAuthServices;


class OAuthServiceProvider:
	
	def __init__(self, requestTokenURL, userAuthorizationURL, accessTokenURL):
		self.requestTokenURL = requestTokenURL;
		self.userAuthorizationURL = userAuthorizationURL;
		self.accessTokenURL = accessTokenURL;
	

# The OAuth service located in the gadget xml inside ModulePrefs + OAuth.

class OAuthService:
	
	__URL_ATTR_ = "url";
	__PARAM_LOCATION_ATTR_ = "param_location";
	__METHOD_ATTR_ = "method";
	
	def __init__(self, service):
		attrs = service.attributes();
		self.__name_ = str(attrs['name']);
		self.__requestUrl_ = self.__parseEndPoint_(service.Request.attributes());
		self.__authorizationUrl_ = self.__parseEndPoint_(service.Authorization.attributes());
		self.__accessUrl_ = self.__parseEndPoint_(service.Access.attributes());

	def __parseEndPoint_(self, element):
		url = str(element[OAuthService.URL_ATTR]);
		if (len(url) == 0):
			raise SpecParserException, "Not an HTTP url";
		
		location = Location.header;
		locationString = str(element[OAuthService.PARAM_LOCATION_ATTR]);
		if (len(locationString) != 0):
			location = locationString;

		method = Method.GET;
		methodString = str(element[OAuthService.METHOD_ATTR]);
		if (len(methodString) != 0):
			method = methodString;
		
		return EndPoint(url, method, location);
	

	def getName(self):
		return self.__name_;

	def getRequestUrl(self):
		return self.__requestUrl_;

	def getAuthorizationUrl(self):
		return self.__authorizationUrl_;

	def getAccessUrl(self):
		return self.__accessUrl_;


# Method to use for requests to an OAuth request token or access token URL.

class Method:
	GET = "GET";
	POST = "POST";

# Location for OAuth parameters in requests to an OAuth request token,
# access token, or resource URL.  (Lowercase to match gadget spec schema)

class Location:
	header = "header";
	url = "url";
	body = "body";

# Description of an OAuth request token or access token URL.
class EndPoint:

	def __init__(self, url, method, location):
		self.url = url;
		self.method = method;
		self.location = location;
	

# Bundles information about a proxy request that requires OAuth

class OAuthRequestParams:
	SERVICE_PARAM = "OAUTH_SERVICE_NAME";
	TOKEN_PARAM = "OAUTH_TOKEN_NAME";
	REQUEST_TOKEN_PARAM = "OAUTH_REQUEST_TOKEN";
	REQUEST_TOKEN_SECRET_PARAM = "OAUTH_REQUEST_TOKEN_SECRET";
	CLIENT_STATE_PARAM = "oauthState";
	BYPASS_SPEC_CACHE_PARAM = "bypassSpecCache";
	
	def __init__(self):
		self._serviceName = self.getParam(OAuthRequestParams.SERVICE_PARAM, "");
		self._tokenName = self.getParam(OAuthRequestParams.TOKEN_PARAM, "");
		self._requestToken = self.getParam(OAuthRequestParams.REQUEST_TOKEN_PARAM, None);
		self._requestTokenSecret = self.getParam(OAuthRequestParams.REQUEST_TOKEN_SECRET_PARAM, None);
		self._origClientState = self.getParam(OAuthRequestParams.CLIENT_STATE_PARAM, None);
		self._bypassSpecCache = self.parseBypassSpecCacheParam();

	def __getParam(self, name, defs):
		val = None;
		if (isset(_REQUEST[name])):
			val = _REQUEST[name];

		if (val == None):
			val = defs;
		
		return val;
	

	def getBypassSpecCache(self):
		return self._bypassSpecCache;

	def getRequestToken(self):
		return self._requestToken;
	

	def getRequestTokenSecret(self):
		return self._requestTokenSecret;

	@staticmethod
	def parseBypassSpecCacheParam():
		if (isset(_REQUEST[OAuthRequestParams.BYPASS_SPEC_CACHE_PARAM])):
			return "1" == _REQUEST[OAuthRequestParams.BYPASS_SPEC_CACHE_PARAM];
		
		return False;

	def getServiceName(self):
		return self._serviceName;

	def getTokenName(self):
		return self._tokenName;
	

	def getOrigClientState(self):
		return self._origClientState;

# Produces OAuth content fetchers for input tokens.

class OAuthFetcherFactory:
	
	def __init__(self, fetcher = None, oauthCrypter = None, tokenStore = None):
		#used to encrypt state stored on the client
		self._oauthCrypter;
		
		#persistent storage for OAuth tokens
		self._tokenStore;

		if (oauthCrypter != None and tokenStore != None):
			return self._OAuthFetcherFactoryCreate(oauthCrypter, tokenStore);
		elif (fetcher != None):
			return self.OAuthFetcherFactoryInit(fetcher);
		else:
			raise Exception('Wrong number of parameters in the OAuthFetcherFactory constuct');

	
	# Initialize the OAuth factory with a default implementation of
	# BlobCrypter and consumer keys/secrets read from oauth.js
	
	def OAuthFetcherFactoryInit(self, fetcher):
		try:
			BBC = BasicBlobCrypter();
			self._oauthCrypter = BasicBlobCrypter(srand(BBC.MASTER_KEY_MIN_LEN));
			specFactory = BasicGadgetSpecFactory(fetcher);
			basicStore = BasicGadgetOAuthTokenStore(BasicOAuthStore(), specFactory);
			basicStore.initFromConfigFile(fetcher);
			self._tokenStore = basicStore;
		except:
			pass;

	
	# Creates an OAuthFetcherFactory based on prepared crypter and token store.
	
	# @param oauthCrypter used to wrap client side state
	# @param tokenStore used as interface to persistent token store.
	
	def _OAuthFetcherFactoryCreate(self, oauthCrypter, tokenStore):
		self._oauthCrypter = oauthCrypter;
		self._tokenStore = tokenStore;
	
	# Produces an OAuthFetcher that will sign requests and delegate actual
	# network retrieval to the (@code nextFetcher}
	
	# @param nextFetcher The fetcher that will fetch real content
	# @param token The gadget token used to identity the user and gadget
	# @param params The parsed parameters the gadget requested
	# @return The oauth fetcher.
	# @throws GadgetException
	
	def getOAuthFetcher(self, nextFetcher, token, params):
		fetcher = OAuthFetcher(self._tokenStore, self._oauthCrypter, nextFetcher, token, params);
		return fetcher;

# Implements the OAuth dance (http://oauth.net/core/1.0/) for gadgets.

# Reading the example in the appendix to the OAuth spec will be helpful to
# those reading this code.

# This class is not thread-safe; create a one for each request that
# requires OAuth signing.
from src.common import RemoteContentFetcher;
class OAuthFetcher (RemoteContentFetcher):	
	# We store some blobs of data on the client for later reuse; the blobs
	# contain key/value pairs, and these are the key names.
	__REQ_TOKEN_KEY_ = "r";
	__REQ_TOKEN_SECRET_KEY_ = "rs";
	__ACCESS_TOKEN_KEY_ = "a";
	__ACCESS_TOKEN_SECRET_KEY_ = "as";
	__OWNER_KEY_ = "o";
	
	# names for the JSON values we return to the client
	CLIENT_STATE = "oauthState";
	APPROVAL_URL = "oauthApprovalUrl";
	ERROR_CODE = "oauthError";
	ERROR_TEXT = "oauthErrorText";
	# names of additional OAuth parameters we include in outgoing requests
	XOAUTH_APP_URL = "xoauth_app_url";
	
	
	# Maximum age for our client state; if this is exceeded we start over. One
	# hour is a fairly arbitrary time limit here.
	
	__CLIENT_STATE_MAX_AGE_SECS_ = 3600;
	
	
	
	# @param oauthCrypter used to encrypt transient information we store on the
	#        client.
	# @param authToken user's gadget security token
	# @param params OAuth fetch parameters sent from makeRequest
	# @param tokenStore storage for long lived tokens.	
	def __init__(self, tokenStore, oauthCrypter, nextFetcher, authToken, params):
	
		# The gadget security token, with info about owner/viewer/gadget.
		
		self._authToken;
		
		
		# Parameters from makeRequest
		
		self._requestParams;
		
		
		# Reference to our persistent store for OAuth metadata.
		
		self._tokenStore;
		
		
		# The accessor we use for signing messages. This also holds metadata about
		# the service provider, such as their URLs and the keys we use to access
		# those URLs.
		
		self.__accessorInfo_;
		
		
		# We use this to encrypt and sign the state we cache on the client.
		
		self.__oauthCrypter_;
		
		
		# State the client sent with their request.
		
		self.__origClientState_ = {};
		
		
		# The request the client really wants to make.
		
		self.__realRequest_;
		
		
		
		# Whether or not we're supposed to ignore the spec cache when referring
		# to the gadget spec for information (e.g. OAuth URLs).
		
		self.__bypassSpecCache_;
		
		self.__responseMetadata_ = {};

		parent.setNextFetcher(nextFetcher);
		
		self.__oauthCrypter_ = oauthCrypter;
		self.authToken = authToken;
		self.__bypassSpecCache_ = params.getBypassSpecCache();
		self._requestParams = params;
		self.__newClientState_ = None;
		self.__aznUrl_ = None;
		self.__error_ = None;
		self.__error_Text_ = None;

		origClientState = params.getOrigClientState();
		if (origClientState != None and str(origClientState) > 0):
			try:
				self.__origClientState_ = self.__oauthCrypter_.unwrap(origClientState, OAuthFetcher.CLIENT_STATE_MAX_AGE_SECS);
			except:
				# Probably too old, pretend we never saw it at all.
				pass;

		if (self.__origClientState_ == None):
			self.__origClientState_ = {};
		
		self._tokenStore = tokenStore;
	

	def __buildErrorResponse(self, e):
		if (self.__error_ == None):
			self.__error_ = OAuthError.UNKNOWN_PROBLEM;
		
		# Take a giant leap of faith and assume that the exception message
		# will be useful to a gadget developer.  Also include the exception
		# stack trace, in case the problem report makes it to someone who knows
		# enough to do something useful with the stack.
		errorBuf = '';
		errorBuf = errorBuf + e.value;
		errorBuf = errorBuf + "\n\n";
		self.__error_Text = errorBuf;
		return self.buildNonDataResponse();
	

	def __buildNonDataResponse(self):
		return self.addResponseMetadata();

	
	# Retrieves metadata from our persistent store.
	
	# @throws GadgetException
	
	def _lookupOAuthMetadata(self):
		tokenKey = self.buildTokenKey();
		self.__accessorInfo_ = self._tokenStore.getOAuthAccessor(tokenKey, self.__bypassSpecCache_);
		# The persistent data store may be out of sync with reality; we trust
		# the state we stored on the client to be accurate.
		accessor = self.__accessorInfo_.getAccessor();
		if (self.__origClientState_.has_key(OAuthFetcher.REQ_TOKEN_KEY)):
			accessor.requestToken = self.__origClientState_[OAuthFetcher.REQ_TOKEN_KEY];
			accessor.tokenSecret = self.__origClientState_[OAuthFetcher.REQ_TOKEN_SECRET_KEY];
		else:
			if (self.__origClientState_.has_key(OAuthFetcher.ACCESS_TOKEN_KEY)):
				accessor.accessToken = self.__origClientState_[OAuthFetcher.ACCESS_TOKEN_KEY];
				accessor.tokenSecret = self.__origClientState_[OAuthFetcher.ACCESS_TOKEN_SECRET_KEY];
			else:
				if (accessor.accessToken == None and self._requestParams.getRequestToken() != None):
					# We don't have an access token yet, but the client sent us a
					# (hopefully) preapproved request token.
					accessor.requestToken = requestParams.getRequestToken();
					accessor.tokenSecret = requestParams.getRequestTokenSecret();
				

	def __buildTokenKey_(self):
		tokenKey = TokenKey();
		# need to URLDecode so when comparing with the ProviderKey it goes thought
		tokenKey.setGadgetUri(urldecode(self.authToken.getAppUrl()));
		tokenKey.setModuleId(self.authToken.getModuleId());
		tokenKey.setServiceName(self._requestParams.getServiceName());
		tokenKey.setTokenName(self._requestParams.getTokenName());
		# At some point we might want to let gadgets specify whether to use OAuth
		# for the owner, the viewer, or someone else. For now always using the
		# owner identity seems reasonable.
		tokenKey.setUserId(self.authToken.getOwnerId());
		return tokenKey;

	def fetch(self, request):
		try:
			self.lookupOAuthMetadata();
		except:
			self.__error_ = OAuthError.BAD_OAUTH_CONFIGURATION;
			return self.buildErrorResponse(e);

		self.__realRequest_ = request;
		response = self.fetchRequest(request);
		return response;

	def fetchRequest(self, request):
		if (self.needApproval()):
			# This is section 6.1 of the OAuth spec.
			self.checkCanApprove();
			self.fetchRequestToken();
			# This is section 6.2 of the OAuth spec.
			self.buildClientApprovalState();
			self.buildAznUrl();
			# break out of the content fetching chain, we need permission from
			# the user to do this
			return self.buildOAuthApprovalResponse();
		elif (self.needAccessToken()):
			# This is section 6.3 of the OAuth spec
			self.checkCanApprove();
			self.exchangeRequestToken();
			self.saveAccessToken();
			self.buildClientAccessState();
		
		return self.fetchData();

	def __buildOAuthApprovalResponse_(self):
		return self.buildNonDataResponse();

	
	# Do we need to get the user's approval to access the data?
	
	def __needApproval_(self):
		if (self.__accessorInfo_ == None):
			return True;
		else:
			return (self.__accessorInfo_.getAccessor().requestToken == None and self.__accessorInfo_.getAccessor().accessToken == None);
		
	
	# Make sure the user is authorized to approve access tokens.  At the moment
	# we restrict this to page owner's viewing their own pages.
	# @throws GadgetException
	def __checkCanApprove(self):
		pageOwner = self.authToken.getOwnerId();
		pageViewer = self.authToken.getViewerId();
		stateOwner = self.__origClientState_[OAuthFetcher.OWNER_KEY];
		if (pageOwner != pageViewer):
			from src.gadgets.servlet import GadgetException;
			raise GadgetException, "Only page owners can grant OAuth approval";
		
		if (stateOwner != None and stateOwner != pageOwner):
			from src.gadgets.servlet import GadgetException;
			raise GadgetException, "Client state belongs to a different person.";
	
	
	# @throws GadgetException
	
	def __fetchRequestToken_(self):
		try:
			accessor = self.__accessorInfo_.getAccessor();
			#TODO The implementations of oauth differs from the one in JAVA. Fix the type OAuthMessage
			url = accessor.consumer.callback_url.requestTokenURL;
			msgParams = {};
			msgParams[OAuthFetcher.XOAUTH_APP_URL] = self.authToken.getAppUrl();
			request = self.newRequestMessageParams(url.url, msgParams);
			reply = self.sendOAuthMessage(request);
			reply.requireParameters([OAuth.OAUTH_TOKEN, OAuth.OAUTH_TOKEN_SECRET]);
			accessor.requestToken = reply.get_parameter(OAuth.OAUTH_TOKEN);
			accessor.tokenSecret = reply.get_parameter(OAuth.OAUTH_TOKEN_SECRET);
		except:
			# It's unfortunate the OAuth libraries raise a generic Exception.
			from src.gadgets.servlet import GadgetException;
			raise GadgetException, e;
		
	

	def __newRequestMessageMethod_(self, method, url, params):
		if (params == None):
			raise Exception, "params was None in  newRequestMessage Use newRequesMessage if you don't have a params to pass";
		
		if (self.__accessorInfo_.getSignatureType() == OAuth.RSA_SHA1):
			params[OAuth.OAUTH_SIGNATURE_METHOD] = OAuth.RSA_SHA1;
		elif (self.__accessorInfo_.getSignatureType() == "PLAINTEXT"):
			params[OAuth.OAUTH_SIGNATURE_METHOD] = "PLAINTEXT";
		else:
			params[OAuth.OAUTH_SIGNATURE_METHOD] = OAuth.HMAC_SHA1;

		accessor = self.__accessorInfo_.getAccessor();
		return accessor.newRequestMessage(method, url, params);

	# @deprecated (All outgoing messages must send additional params
	# like XOAUTH_APP_URL, so use newRequestMessageParams instead)
	
	def __newRequestMessageUrlOnly_(self, url):
		params = {};
		return self.newRequestMessageParams_(url, params);

	def __newRequestMessageParams_(self, url, params):
		method = "POST";
		if (self.__accessorInfo_.getHttpMethod() == OAuthStoreVars.HttpMethod['GET']):
			method = "GET";
		
		return self.newRequestMessageMethod(method, url, params);
	

	def __newRequestMessage_(self, url = None, method = None, params = None):
		if (method != None and url != None and params != None):
			return self.newRequestMessageMethod(method, url, params);
		else:
			if (url != None and params != None):
				return self.newRequestMessageParams(url, params);
			else:
				if (url != None):
					return self.newRequestMessageUrlOnly(url);
				

	def __getAuthorizationHeader_(self, oauthParams):
		result = "OAuth ";
		first = True;
		for key in oauthParams.keys():
			val = oauthParams[key];
			if (not first):
				result = result  + ", ";
			else:
				first = False;
			
			result = result + OAuthUtil.urlencodeRFC3986(key) + "=\"" + OAuthUtil.urlencodeRFC3986(val) + '"';
		
		return result;
	

	def __createRemoteContentRequest_(self, oauthParams, method, url, headers, contentType, postBody, options):
		paramLocation = self.__accessorInfo_.getParamLocation();
		newHeaders = {};
		# paramLocation could be overriden by a run-time parameter to fetchRequest

		if (paramLocation == OAuthStoreVars.OAuthParamLocation['AUTH_HEADER']):
			if (headers != None):
				newHeaders = headers;
			
			authHeader = {};
			authHeader = self.getAuthorizationHeader(oauthParams);
			newHeaders["Authorization"] = authHeader;
			
			
		elif(paramLocation == OAuthStoreVars.OAuthParamLocation['POST_BODY']):
			if (not OAuthUtil.isFormEncoded(contentType)):
				from src.gadgets.servlet import GadgetException;
				raise GadgetException, "Invalid param: OAuth param location can only be post_body if post body if of type x-www-form-urlencoded";
			
			if (postBody == None or len(postBody) == 0):
				postBody = OAuthUtil.getPostBodyString(oauthParams);
			else:
				postBody = postBody + "&" + OAuthUtil.getPostBodyString(oauthParams);
			
		elif (paramLocation == OAuthStoreVars.OAuthParamLocation['URI_QUERY']):
			url = OAuthUtil.addParameters(url, oauthParams);

		postBodyBytes = None; #(postBody == None) ? None : None; # postBody.getBytes("UTF-8"); # See what can we do with this?
		rcr = RemoteContentRequest(url);
		rcr.createRemoteContentRequest(method, url, newHeaders, postBodyBytes, options);
		return rcr;
	
	# Sends OAuth request token and access token messages.
	
	def __sendOAuthMessage_(self, request):
		rcr = self.createRemoteContentRequest(self.filterOAuthParams(request), request.get_normalized_http_method(), request.get_url(), None, RemoteContentRequest.DEFAULT_CONTENT_TYPE, None, RemoteContentRequest.getDefaultOptions());
		content = self.getNextFetcher().fetchRequest(rcr);
		reply = OAuthRequest.from_request();
		params = OAuthUtil.decodeForm(content.getResponseContent());
		reply.set_parameters(params);
		return reply;

	# Builds the data we'll cache on the client while we wait for approval.	
	def __buildClientApprovalState_(self):
		try:
			accessor = self.__accessorInfo_.getAccessor();
			oauthState = {};
			oauthState[OAuthFetcher.REQ_TOKEN_KEY] = accessor.requestToken;
			oauthState[OAuthFetcher.REQ_TOKEN_SECRET_KEY] = accessor.tokenSecret;
			oauthState[OAuthFetcher.OWNER_KEY] = self.authToken.getOwnerId();
			self.__newClientState_ = self.__oauthCrypter_.wrap(oauthState);
		except:
			from src.gadgets.servlet import GadgetException;
			raise GadgetException, "INTERNAL SERVER ERROR: " + e.value;
		
	
	# Builds the URL the client needs to visit to approve access.	
	def __buildAznUrl_(self):
		# At some point we can be clever and use a callback URL to improve
		# the user experience, but that's too complex for now.
		accessor = self.__accessorInfo_.getAccessor();
		azn = accessor.consumer.callback_url.userAuthorizationURL;
		authUrl = azn.url;
		if (authUrl.pos("?") == - 1):
			authUrl = authUrl + "?";
		else:
			authUrl = authUrl + "&";
		
		authUrl = authUrl + OAuth.OAUTH_TOKEN;
		authUrl = authUrl + "=";
		authUrl = authUrl + OAuthUtil.urlencodeRFC3986(accessor.requestToken);
		self.__aznUrl_ = authUrl;
		
	# Do we need to exchange a request token for an access token?
	def __needAccessToken_(self):
		return (self.__accessorInfo_.getAccessor().requestToken != None and self.__accessorInfo_.getAccessor().accessToken == None);
	
	# Implements section 6.3 of the OAuth spec.
	def __exchangeRequestToken_(self):
		try:
			accessor = self.__accessorInfo_.getAccessor();
			url = accessor.consumer.callback_url.accessTokenURL;
			msgParams = {};
			msgParams[OAuthFetcher.XOAUTH_APP_URL] = self.authToken.getAppUrl();
			msgParams[OAuth.OAUTH_TOKEN] = accessor.requestToken;
			request = self.newRequestMessageParams(url.url, msgParams);
			reply = self.sendOAuthMessage(request);
			reply.requireParameters([Auth.OAUTH_TOKEN, OAuth.OAUTH_TOKEN_SECRET]);
			accessor.accessToken = reply.get_parameter(OAuth.OAUTH_TOKEN);
			accessor.tokenSecret = reply.get_parameter(OAuth.OAUTH_TOKEN_SECRET);
		except:
			from src.gadgets.servlet import GadgetException;
			# It's unfortunate the OAuth libraries raise a generic Exception.
			raise GadgetException, "INTERNAL SERVER ERROR: " + e;
	
	# Save off our token and secret to the persistent store.	
	# @throws GadgetException	
	def __saveAccessToken_(self):
		accessor = self.__accessorInfo_.getAccessor();
		tokenKey = self.buildTokenKey();
		tokenInfo = TokenInfo(accessor.accessToken, accessor.tokenSecret);
		self._tokenStore.storeTokenKeyAndSecret(tokenKey, tokenInfo);
	
	# Builds the data we'll cache on the client while we make requests.	
	def __buildClientAccessState_(self):
		try:
			oauthState = {};
			accessor = self.__accessorInfo_.getAccessor();
			oauthState[OAuthFetcher.ACCESS_TOKEN_KEY] = accessor.accessToken;
			oauthState[OAuthFetcher.ACCESS_TOKEN_SECRET_KEY] = accessor.tokenSecret;
			oauthState[OAuthFetcher.OWNER_KEY] = self.authToken.getOwnerId();
			self.__newClientState_ = self.__oauthCrypter_.wrap(oauthState);
		except:
			from src.gadgets.servlet import GadgetException;
			raise GadgetException, "INTERNAL SERVER ERROR: " + e;
	
	# Get honest-to-goodness user data.	
	def __fetchData_(self):
		try:
			msgParams = OAuthUtil.urldecodeRFC3986(self.__realRequest_.getPostBody()) if OAuthUtil.isFormEncoded(self.__realRequest_.getContentType()) else {};
			method = self.__realRequest_.getMethod();
			msgParams[OAuthFetcher.XOAUTH_APP_URL] = self.authToken.getAppUrl();
			# Build and sign the message.
			oauthRequest = self.newRequestMessageMethod(method, self.__realRequest_.getUrl(), msgParams);
			rcr = self.createRemoteContentRequest(self.filterOAuthParams(oauthRequest), self.__realRequest_.getMethod(), self.__realRequest_.getUrl(), self.__realRequest_.getHeaders(), self.__realRequest_.getContentType(), self.__realRequest_.getPostBody(), self.__realRequest_.getOptions());
			content = self.getNextFetcher().fetchRequest(rcr);
			# TODO is there a better way to detect an SP error?
			statusCode = content.getHttpCode();
			if (statusCode >= 400 and statusCode < 500):
				message = self.parseAuthHeader(None, content);
				if (message.get_parameter(OAuth.OAUTH_PROBLEM) != None):
					raise OAuthProtocolException, message;
				
			# Track metadata on the response
			self.addResponseMetadata();
			return content;
		except:
			from src.gadgets.servlet import GadgetException;
			raise GadgetException, "INTERNAL SERVER ERROR: " + e;
	
	# Parse OAuth WWW-Authenticate header and either add them to an existing
	# message or create a message.
	# @param msg
	# @param resp
	# @return the updated message.
	
	def __parseAuthHeader_(self, resp, msg = None):
		if (msg == None):
			msg = OAuthRequest.from_request();

		authHeaders = resp.getResponseHeader("WWW-Authenticate");
		if (authHeaders != None):
			msg.set_parameters(OAuthUtil.decodeAuthorization(authHeaders));
		
		return msg;

	
	# Extracts only those parameters from an OAuthMessage that are OAuth-related.
	# An OAuthMessage may hold a whole bunch of non-OAuth-related parameters
	# because they were all needed for signing. But when constructing a request
	# we need to be able to extract just the OAuth-related parameters because
	# they, and only they, may have to be put into an Authorization: header or
	# some such thing.
	
	# @param message the OAuthMessage object, which holds non-OAuth parameters
	# such as foo=bar (which may have been in the original URI query part, or
	# perhaps in the POST body), as well as OAuth-related parameters (such as
	# oauth_timestamp or oauth_signature).
	
	# @return a list that contains only the oauth_related parameters.
	
	# @throws IOException
	
	def __filterOAuthParams_(message):
		result = {};
		for key in message.get_parameters().keys():
			value = message.get_parameters()[key];
			if (key.lower().find("oauth") != - 1 or key.lower().find("xoauth") != - 1):
				result[key] = value;
			
		
		return result;
	

	def getResponseMetadata(self):
		return self.__responseMetadata_;

	def addResponseMetadata(self):
		if (self.__newClientState_ != None):
			self.__responseMetadata_[OAuthFetcher.CLIENT_STATE] = self.__newClientState_;

		if (self.__aznUrl_ != None):
			self.__responseMetadata_[OAuthFetcher.APPROVAL_URL] = self.__aznUrl_;
		
		if (self.__error_ != None):
			self.__responseMetadata_[OAuthFetcher.ERROR_CODE] = self.__error_;
		
		if (self.__error_Text != None):
			self.__responseMetadata_[OAuthFetcher.ERROR_TEXT] = self.__error_Text;





# Error strings to be returned to gadgets as "oauthError" data.
class OAuthError:
	# The request cannot be completed because the OAuth configuration for
	# the gadget is incorrect.
	BAD_OAUTH_CONFIGURATION = "BAD_OAUTH_CONFIGURATION";
	
	# The request cannot be completed for an unspecified reason.
	UNKNOWN_PROBLEM = "UNKNOWN_PROBLEM";
	

class OAuthAccessor:
	

	def __init__(self, consumer):
		self.__properties_ = {};
		self.consumer = consumer;
		self.requestToken = None;
		self.accessToken = None;
		self.tokenSecret = None;
	

	def getProperty(self, name):
		return self.__properties_[name];

	def setProperty(self, name, value):
		self.__properties_[name] = value;

	def newRequestMessage(self, method, url, parameters):
		if (method == None):
			method = self.getProperty("httpMethod");
			if (method == None):
				method = self.consumer.getProperty("httpMethod");
				if (method == None):
					method = "GET";
				

		message = OAuthRequest.from_consumer_and_token(self.consumer, self.accessToken, method, url, parameters);
		signatureMethod = None;
		if (parameters[OAuth.OAUTH_SIGNATURE_METHOD] == OAuth.RSA_SHA1):
			signatureMethod = OAuthSignatureMethod_RSA_SHA1();
		else:
			if (parameters[OAuth.OAUTH_SIGNATURE_METHOD] == OAuth.HMAC_SHA1):
				signatureMethod = OAuthSignatureMethod_HMAC_SHA1();
			else: # PLAINTEXT
				signatureMethod = OAuthSignatureMethod_PLAINTEXT();
			
		message.sign_request(signatureMethod, self.consumer, self.tokenSecret);
		return message;
	

class OAuth:
	VERSION_1_0 = "1.0";
	ENCODING = "UTF-8";
	FORM_ENCODED = "application/x-www-form-urlencoded";
	OAUTH_CONSUMER_KEY = "oauth_consumer_key";
	OAUTH_TOKEN = "oauth_token";
	OAUTH_TOKEN_SECRET = "oauth_token_secret";
	OAUTH_SIGNATURE_METHOD = "oauth_signature_method";
	OAUTH_SIGNATURE = "oauth_signature";
	OAUTH_TIMESTAMP = "oauth_timestamp";
	OAUTH_NONCE = "oauth_nonce";
	OAUTH_VERSION = "oauth_version";
	HMAC_SHA1 = "HMAC_SHA1";
	RSA_SHA1 = "RSA_SHA1";
	BEGIN_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----";
	END_PRIVATE_KEY = "-----END PRIVATE KEY-----";
	OAUTH_PROBLEM = "oauth_problem";

class OAuthException(Exception):
	pass;

class OAuthProblemException(Exception):
	pass;

class OAuthProtocolException (Exception):
	pass;

class OAuthConsumer:
	def __init__(key, secret, callback_url = None):
		self.__properties_ = {};
		self.key = key;
		self.secret = secret;
		self.callback_url = callback_url;

	def getProperty(self, name):
		return self.__properties_[name];

	def setProperty(self, name, value):
		self.__properties_[name] = value;

class OAuthToken:
	def __init__(self, key, secret):
		self.key = key;
		self.secret = secret;
	
	# generates the basic string serialization of a token that a server
	# would respond to request_token and access_token calls with
	def to_string(self):
		return "oauth_token=" + OAuthUtil.urlencodeRFC3986(self.key) + "&oauth_token_secret=" + OAuthUtil.urlencodeRFC3986(self.secret);
	

	def __toString_(self):
		return self.to_string();

class OAuthSignatureMethod:

	def check_signature(self, request, consumer, token, signature):
		built = self.build_signature(request, consumer, token);
		return built == signature;


class OAuthSignatureMethod_HMAC_SHA1(OAuthSignatureMethod):
	def get_name(self):
		return "HMAC-SHA1";

	def build_signature(self, request, consumer, token):
		base_string = request.get_signature_base_string();
		request.base_string = base_string;
		key_parts = [consumer.secret, (token if (token != None) else "")];
		key_parts = array_map(['OAuthUtil', 'urlencodeRFC3986'], key_parts);
		key = '&'.join(key_parts);

		return hash_hmac('sha1', base_string, key, True).encode('base64');
	

	# TODO: Double check this!
	def check_signature(self, request, consumer, token, signature):
		sign = self.build_signature(request, consumer, token);
		return sign == signature;

class OAuthSignatureMethod_PLAINTEXT(OAuthSignatureMethod):
	def get_name(self):
		return "PLAINTEXT";

	def build_signature(self, request, consumer, token):
		sig = [OAuthUtil.urlencodeRFC3986(consumer.secret)];
		if (token):
			sig.append(OAuthUtil.urlencodeRFC3986(token.secret));
		else:
			sig.append('');
		
		raw = "&".join(sig);
		# for debug purposes
		request.base_string = raw;
		return OAuthUtil.urlencodeRFC3986(raw);
	

	# TODO: Double check this!
	def check_signature(self, request, consumer, token, signature):
		raw = OAuthUtil.urldecodeRFC3986(request.base_string);
		sig = raw.split("&");
		sig.pop();
		secret = [AuthUtil.urldecodeRFC3986(consumer.secret)];
		return sig == secret;

class OAuthSignatureMethod_RSA_SHA1(OAuthSignatureMethod):
	PRIVATE_KEY = "RSA-SHA1.PrivateKey";

	def get_name(self):
		return "RSA-SHA1";

	def _fetch_public_cert(self, request):
		# not implemented yet, ideas are:
		# (1) do a lookup in a table of trusted certs keyed off of consumer
		# (2) fetch via http using a url provided by the requester
		# (3) some sort of specific discovery code based on request
		# 
		# either way should return a string representation of the certificate
		raise Exception, "fetch_public_cert not implemented";

	def _fetch_private_cert(self, request):
		# not implemented yet, ideas are:
		# (1) do a lookup in a table of trusted certs keyed off of consumer
		# 
		# either way should return a string representation of the certificate
		raise Exception, "fetch_private_cert not implemented";

	def build_signature(self, request, consumer, token):
		base_string = request.get_signature_base_string();
		# Fetch the private key cert based on the request
		cert = consumer.getProperty(OAuthSignatureMethod_RSA_SHA1.PRIVATE_KEY);
		# Pull the private key ID from the certificate
		# FIXME this def seems to be called both for a oauth.json action where
		# there is no phrase required, but for signed requests too, which do require it
		# this is a dirty hack to make it work .. kinda
		privatekeyid = openssl_pkey_get_private(cert);
		if (not privatekeyid):
			privatekeyid = Config.get('private_key_phrase') if (openssl_pkey_get_private(cert, Config.get('private_key_phrase'))) != '' else None;
			if (not privatekeyid):
				raise Exception, "Could not load private key";
			
		# Sign using the key
		signature = '';
		ok = openssl_sign(base_string, signature, privatekeyid);
		if (ok == False):
			raise OAuthException, "Could not create signature";
		
		# Release the key resource
		openssl_free_key(privatekeyid);
		return signature.encode('base64');
	

	def check_signature(self, request, consumer, token, signature):
		decoded_sig = signature.decode('base64');
		base_string = request.get_signature_base_string();
		# Fetch the public key cert based on the request
		cert = self.fetch_public_cert(request);
		# Pull the public key ID from the certificate
		publickeyid = openssl_get_publickey(cert);
		# Check the computed signature against the one passed in the query
		ok = openssl_verify(base_string, decoded_sig, publickeyid);
		# Release the key resource
		openssl_free_key(publickeyid);
		return ok == 1;

class OAuthRequest:
	version = '1.0';

	def __init__(http_method, http_url, parameters = None):
		self.base_string;
		if(parameters == None):
			parameters = {};
		self.__parameters_ = parameters;
		self.__http_method_ = http_method;
		self.__http_url_ = http_url;
	
	# attempt to build up a request from what was passed to the server
	@staticmethod
	def from_request(http_method = None, http_url = None, parameters = None):
		from lib import RequestUtil;
		requestUtilHandler = RequestUtil.getInstance();		

		scheme = 'http' if (not requestUtilHandler.SERVER.has_key('HTTPS') or requestUtilHandler.SERVER['HTTPS'] != "on") else 'https';

		if(http_url == None):
			http_url = scheme + '://' + requestUtilHandler.SERVER['HTTP_HOST'] + requestUtilHandler.SERVER['REQUEST_URI'];

		if(http_method == None):
			http_method = requestUtilHandler.SERVER['REQUEST_METHOD'];

		request_headers = OAuthRequest.get_headers();
		# let the library user override things however they'd like, if they know
		# which parameters to use then go for it, for example XMLRPC might want to
		# do this
		if (parameters):
			req = OAuthRequest(http_method, http_url, parameters);
		elif (request_headers.has_key('Authorization') and request_headers['Authorization'][0:5] == "OAuth"):
			# next check for the auth header, we need to do some extra stuff
			# if that is the case, namely suck in the parameters from GET or POST
			# so that we can include them in the signature
			header_parameters = OAuthRequest.split_header(request_headers['Authorization']);
			req_parameters = requestUtilHandler.GOTORPOST;
			#if (http_method == "GET"):
			#	req_parameters = _GET;
			#else:
			#	if (http_method == "POST"):
			#		req_parameters = _POST;
			
			from lib import Util;
			parameters = Util.array_merge(header_parameters, req_parameters);
			req = OAuthRequest(http_method, http_url, parameters);
		elif (http_method == "GET"):
			req = OAuthRequest(http_method, http_url, _GET);
		elif (http_method == "POST"):
			req = OAuthRequest(http_method, http_url, _POST);
		
		return req;
	
	# pretty much a helper def to set up the request
	@staticmethod
	def from_consumer_and_token(consumer, token, http_method, http_url, parameters = None):
		parameters = parameters if Util.is_array(parameters) else {};
		defaults = {"oauth_nonce" : OAuthRequest.generate_nonce(), 
				"oauth_timestamp" : OAuthRequest.generate_timestamp(), 
				"oauth_consumer_key" : consumer.key};
		parameters = Util.array_merge(defaults, parameters);
		if (token != None):
			parameters['oauth_token'] = token;
		
		return OAuthRequest(http_method, http_url, parameters);

	def set_parameter(self, name, value):
		self.__parameters_[name] = value;
	

	def get_parameter(self, name):
		return self.__parameters_[name];

	def get_parameters(self):
		return self.__parameters_;

	def set_parameters(self, params):
		self.__parameters_ = params;
		return self.__parameters_;

	# TODO double check if hash can be used
	def requireParameters(self, names):
		present = self.__parameters_;
		absent = {};
		for required in names:
			if (not present in required):
				absent.append(required);
			
		if (len(absent) == 0):
			raise OAuthProblemException, "oauth_parameters_absent: " + OAuthUtil.urlencodeRFC3986(absent);

	
	# Returns the normalized parameters of the request
	# This will be all (except oauth_signature) parameters,
	# sorted first by key, and if duplicate keys, then by
	# value.
	# The returned string will be all the key=value pairs
	# concated by &.
	# @return string	
	def get_signable_parameters(self):
		# Grab all parameters
		params = self.__parameters_;
		# Remove oauth_signature if present
		if (params.has_key('oauth_signature')):
			del(params['oauth_signature']);
		
		# Urlencode both keys and values
		keys = array_map(['OAuthUtil', 'urlencodeRFC3986'], params.keys());
		values = array_map(['OAuthUtil', 'urlencodeRFC3986'], params.values());
		params = array_combine(keys, values);
		# Sort by keys (natsort)
		uksort(params, 'strnatcmp');
		# Generate key=value pairs
		pairs = {};
		for key in params.keys:
			value = params[key];
			if (Util.is_array(value)):
				# If the value is an array, it's because there are multiple
				# with the same key, sort them, then add all the pairs
				natsort(value);
				for v2 in value:
					pairs.append(key + '=' + v2);
				
			else:
				pairs.append(key + '=' + value);

		# Return the pairs, concated with &
		return '&'.join(pairs);
	
	# Returns the base string of this request
	# The base string defined as the method, the url
	# and the parameters (normalized), each urlencoded
	# and the concated with &.
	
	def get_signature_base_string(self):
		tmp = self.__parameters_;
		parts = parse_url(self.__http_url_);
		parse_str(parts['query'], params);
		for key in params.keys():
			value = params[key];
			if (key == "signOwner" or key == "signViewer"):
				continue;
			
			self.__parameters_[key] = value;
		
		parts = [self.get_normalized_http_method(), self.get_normalized_http_url(), 
				self.get_signable_parameters()];
		parts = array_map(['OAuthUtil', 'urlencodeRFC3986'], parts);
		self.__parameters_ = tmp;
		return '&'.join(parts);
	
	# just uppercases the http method	
	def get_normalized_http_method(self):
		return strtoupper(self.__http_method_);
	
	# parses the url and rebuilds it to be
	# scheme:# host/path	
	def get_normalized_http_url(self):
		parts = parse_url(self.__http_url_);
		# FIXME: port should handle according to http://groups.google.com/group/oauth/browse_thread/thread/1b203a51d9590226
		port = ':' + parts['port'] if (parts.has_key('port') and parts['port'] != '80') else '';
		path = parts['path'] if(parts.has_key('path')) else '';
		
		return parts['scheme'] + '://' + parts['host'] + port + path;
	
	# builds a url usable for a GET request	
	def to_url(self):
		out = self.get_normalized_http_url() + "?";
		out = out + self.to_postdata();
		parts = parse_url(self.__http_url_);
		out = out + "&" + parts['query'];
		return out;

	def get_url(self):
		return self.__http_url_;
	
	# builds the data one would send in a POST request
	def to_postdata(self):
		total = {};
		for k in self.__parameters_.keys():
			v = self.__parameters_[k];
			total.append(OAuthUtil.urlencodeRFC3986(k) + "=" + OAuthUtil.urlencodeRFC3986(v));
		
		out = "&".join(total);
		return out;
	
	# builds the Authorization: header
	def to_header(self):
		out = '"Authorization: OAuth realm="",';
		for k in self.__parameters_.keys():
			v = self.__parameters_[k];
			if (k[0:5] != "oauth"):
				continue;
			out = out + ',' + OAuthUtil.urlencodeRFC3986(k) + '="' + OAuthUtil.urlencodeRFC3986(v) + '"';
		
		return out;
	

	def __toString_(self):
		return self.to_url();

	def sign_request(self, signature_method, consumer, token):
		self.set_parameter("oauth_signature_method", signature_method.get_name());
		signature = self.build_signature(signature_method, consumer, token);
		self.set_parameter("oauth_signature", signature);

	def build_signature(self, signature_method, consumer, token):
		signature = signature_method.build_signature(this, consumer, token);
		return signature;
	
	# util function: current timestamp
	@staticmethod
	def __generate_timestamp_():
		return time();

	# util function: current nonce	
	@staticmethod
	def generate_nonce():
		mt = microtime();
		rand = mt_rand();
		return md5(mt + rand); # md5s look nicer than numbers
	
	# util def for turning the Authorization: header into
	# parameters, has to do some unescaping	
	@staticmethod
	def split_header(header):
		# this should be a regex
		# error cases: commas in parameter values
		parts = header.split(",");
		out = {};
		for param in parts:
			param = param.strip();
			# skip the "realm" param, nobody ever uses it anyway
			if (param[0:5] != "oauth"):
				continue;
			param_parts = param.split("=");
			# rawurldecode(self): used because urldecode(self): will turn a "+" in the
			# value into a space
			out[param_parts[0]] = rawurldecode(substr(param_parts[1], 1, - 1));
		
		return out;
	
	# helper to try to sort out headers for people who aren't running apache	
	@staticmethod
	def get_headers():
		if (function_exists('apache_request_headers')):
			# we need this to get the actual Authorization: header
			# because apache tends to tell us it doesn't exist
			return apache_request_headers();
		
		# otherwise we don't have apache and are just going to have to hope
		# that RequestUtil.headers actually contains what we need
		out = {};

		from lib import RequestUtil;
		requestUtilHandler = RequestUtil.getInstance();		

		for key in requestUtilHandler.headers.keys():
			value = requestUtilHandler.headers[key];
			if (key[0:5] == "HTTP_"):
				# this is chaos, basically it is just there to capitalize the first
				# letter of every word that is not an initial HTTP and strip HTTP
				# code from przemek
				key = str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr(key, 5)))));
				out[key] = value;
			
		
		return out;



class OAuthUtil:	
	AUTH_SCHEME = "OAuth";
	__AUTHORIZATION = "\[a-zA-Z0-9*]\ +(.*)";
	__NVP = "(\\S*)\\s*\\=\\s*\"([^\"]*)\"";

	@staticmethod
	def getPostBodyString(params):
		result = '';
		first = True;
		for key in params.keys():
			val = params[key];
			if (first):
				first = False;
			else:
				result = result + '&';
			
			result = result + OAuthUtil.urlencodeRFC3986(key) + "=" + OAuthUtil.urlencodeRFC3986(val);
		
		return result;
	

	@staticmethod
	def urlencodeRFC3986(string):
		import  urllib;
		#return str_replace('%7E', '~', rawurlencode(string));
		return urllib.quote(string).replace('%7E', '~');


	@staticmethod
	def urldecodeRFC3986(string):
		import  urllib;
		#return rawurldecode(string);
		
		return urllib.unquote(string);

	#Return True if the given Content-Type header means FORM_ENCODED.

	@staticmethod
	def isFormEncoded(contentType):
		if (contentType == None):
			return False;
		
		semi = contentType.find(";");
		if (semi >= 0):
			contentType = contentType[0:semi];
		
		return OAuth.FORM_ENCODED.lower() == contentType.strip().lower();
	
	@staticmethod
	def addParameters(url, oauthParams):
		url = url + ('?' if url.find('?') == -1 else '&');
		for key in oauthParams.keys():
			value = oauthParams[key]
			url = url + key + "=" + value + "&";
		
		return url;
	

	@staticmethod
	def decodeForm(form):
		parameters = {};
		explodedForm = form.split("&");
		for params in explodedForm:			
			value = params.split("=");
			if (len(value[0]) > 0 and len(value[1]) > 0):
				parameters[OAuthUtil.urldecodeRFC3986(value[0])] = OAuthUtil.urldecodeRFC3986(value[1]);
			
		return parameters;
	
	# Parse the parameters from an OAuth Authorization or WWW-Authenticate
	# header. The realm is included as a parameter. If the given header doesn't
	# start with "OAuth ", return an empty list.	
	@staticmethod
	def decodeAuthorization(authorization):
		into = {};
		if (authorization != None):
			import re;
			pattern = re.compile(OAuthUtil.__AUTHORIZATION);
			
			m = pattenr.match(authorization);
			#ereg(OAuthUtil.__AUTHORIZATION, authorization);
			if (m == None):
				if (authorization.find(OAuthUtil.AUTH_SCHEME) == 0):
					authorization = authorization.replace("OAuth ", "");
					authParams = authorization.split(", ");
					for params in authParams:
						pattern = re.compile(OAuthUtil.__NVP);
						#m = ereg(OAuthUtil._NVP, params);
						m = pattern.match(params);

						if (m != None):
							keyValue = params.split("=");
							name = OAuthUtil.urlencodeRFC3986(keyValue[0]);
							value = OAuthUtil.urlencodeRFC3986(keyValue[1].replace("\"", ""));
							into[name] = value;

		return into;


from src.gadgets.servlet import GadgetException;
class OAuthStoreException(GadgetException):
	pass;


# Higher-level interface that allows callers to store and retrieve
# OAuth-related data directly from (@code GadgetSpec}s, (@code GadgetContext}s,
# etc. See (@link OAuthStore} for a more detailed explanation of the OAuth
# Data Store.

class GadgetOAuthTokenStore:	
	# Internal class used to communicate results of parsing the gadget spec
	# between methods.
	
	# name of the OAuth feature in the gadget spec
	OAUTH_FEATURE = "oauth";
	# name of the Param that identifies the service name
	SERVICE_NAME = "service_name";
	# name of the Param that identifies the access URL
	ACCESS_URL = "access_url";
	# name of the optional Param that identifies the HTTP method for access URL
	ACCESS_HTTP_METHOD = "access_method";
	# name of the Param that identifies the request URL
	REQUEST_URL = "request_url";
	# name of the optional Param that identifies the HTTP method for request URL
	REQUEST_HTTP_METHOD = "request_method";
	# name of the Param that identifies the user authorization URL
	AUTHORIZE_URL = "authorize_url";
	# name of the Param that identifies the location of OAuth parameters
	OAUTH_PARAM_LOCATION = "param_location";
	AUTH_HEADER = "auth_header";
	POST_BODY = "post_body";
	URI_QUERY = "uri_query";
	
	# DEFAULT_OAUTH_PARAM_LOCATION = AUTH_HEADER;
	DEFAULT_OAUTH_PARAM_LOCATION = "auth_header"; # It has to be like the line above this.
	# TODO: Check why java use AUTH_HEADER
	

	# we use POST if no HTTP method is specified for access and request URLs
	# (user authorization always uses GET)
	DEFAULT_HTTP_METHOD = "POST";
	
	# Public constructor.
	# @param store an (@link OAuthStore} that can store and retrieve OAuth
	#              tokens, as well as information about service providers.

	def __init__(self, store, specFactory):
		self.__store_ = store;
		self.__gadgetSpec_;
		self.__specFactory_ = specFactory;
	
	# Stores a negotiated consumer key and secret in the gadget store.
	# The "secret" can either be a consumer secret in the strict OAuth sense,
	# or it can be a PKCS8-then-Base64 encoded private key that we'll be using
	# with this service provider.
	# @param gadgetUrl the URL of the gadget
	# @param serviceName the service provider with whom we have negotiated a
	#                    consumer key and secret.
	
	def storeConsumerKeyAndSecret(self, gadgetUrl, serviceName, keyAndSecret):
		providerKey = ProviderKey();
		providerKey.setGadgetUri(gadgetUrl);
		providerKey.setServiceName(serviceName);
		self.store.setOAuthConsumerKeyAndSecret(providerKey, keyAndSecret);
	
	# Stores an access token in the OAuth Data Store.
	# @param tokenKey information about the Gadget storing the token.
	# @param tokenInfo the TokenInfo to be stored in the OAuth data store.
	def storeTokenKeyAndSecret(self, tokenKey, tokenInfo):
		getGadgetUri = tokenKey.getGadgetUri();
		if (len(getGadgetUri) == 0):
			raise Exception, "found empty gadget URI in TokenKey";
		
		getUserId = tokenKey.getUserId();
		if (len(getUserId) == 0):
			raise Exception, "found empty userId in TokenKey";
		
		self.store.setTokenAndSecret(tokenKey, tokenInfo);
	
	# Retrieve an OAuthAccessor that is ready to sign OAuthMessages.
	# @param tokenKey information about the gadget retrieving the accessor.
	# @return an OAuthAccessorInfo containing an OAuthAccessor (whic can be
	#         passed to an OAuthMessage.sign method), as well as httpMethod and
	#         signatureType fields.
	
	def getOAuthAccessor(self, tokenKey, ignoreCache):
		gadgetUri = tokenKey.getGadgetUri();
		if (len(gadgetUri) == 0):
			raise OAuthStoreException, "found empty gadget URI in TokenKey";
		
		getUserId = tokenKey.getUserId();
		if (len(getUserId) == 0):
			raise OAuthStoreException, "found empty userId in TokenKey";
		
		gadgetSpec = self.specFactory.getGadgetSpecUri(gadgetUri, ignoreCache);
		provInfo = self.getProviderInfo(gadgetSpec, tokenKey.getServiceName());
		return self.store.getOAuthAccessorTokenKey(tokenKey, provInfo);
	
	
	# Reads OAuth provider information out of gadget spec.
	# @param spec
	# @return a GadgetInfo
	@staticmethod
	def getProviderInfo(spec, serviceName):
		oauthSpec = spec.getOAuthSpec();
		if (oauthSpec == None):
			message = "gadget spec is missing /ModulePrefs/OAuth section";
			from src.gadgets.servlet import GadgetException;
			raise GadgetException, message;
		
		services = oauthSpec.getServices();
		service = None;
		if (services.has_key(serviceName)):
			service = services[serviceName];
		
		if (service == None):
			message = '';
			message = message + "Spec does not contain OAuth service '";
			message = message + serviceName;
			message = message + "'.  Known services: ";
			for key in services.keys():
				value = services[key];
				message = message + "'";
				message = message + key;
				message = message + "'";
				message = message + ", ";
			
			from src.gadgets.servlet import GadgetException;
			raise GadgetException, message;
		
		provider = OAuthServiceProvider(service.getRequestUrl(), service.getAuthorizationUrl(), service.getAccessUrl());
		httpMethod = None;

		if (service.getRequestUrl().method == "GET"):
			httpMethod = OAuthStoreVars.HttpMethod['GET'];
		else:
			httpMethod = OAuthStoreVars.HttpMethod['POST'];
		
		paramLocation = None;
		
		if(service.getRequestUrl().location == "URL"):
			paramLocation = OAuthStoreVars.OAuthParamLocation['URI_QUERY'];
		if (service.getRequestUrl().location == "BODY"):
			paramLocation = OAuthStoreVars.OAuthParamLocation['POST_BODY'];
		else:
			paramLocation = OAuthStoreVars.OAuthParamLocation['AUTH_HEADER'];
		
		provInfo = ProviderInfo();
		provInfo.setHttpMethod(httpMethod);
		provInfo.setParamLocation(paramLocation);
		# TODO: for now, we'll just set the signature type to HMAC_SHA1
		# as this will be ignored later on when retrieving consumer information.
		# There, if we find a negotiated HMAC key, we will use HMAC_SHA1. If we
		# find a negotiated RSA key, we will use RSA_SHA1. And if we find neither,
		# we may use RSA_SHA1 with a default signing key.
		provInfo.setSignatureType(OAuthStoreVars.SignatureType['HMAC_SHA1']);
		provInfo.setProvider(provider);
		return provInfo;
	
	# Extracts a single oauth-related parameter from a key-value map,
	# throwing an exception if the parameter could not be found (unless the
	# parameter is optional, in which case None is returned).
	
	# @param params the key-value map from which to pull the value (parameter)
	# @param paramName the name of the parameter (key).
	# @param isOptional if it's optional, don't raise an exception if it's not
	#                   found.
	# @return the value corresponding to the key (paramName)
	# @throws GadgetException if the parameter value couldn't be found.
	
	@staticmethod
	def getOAuthParameter(params, paramName, isOptional):
		param = params[paramName];
		if (param == None and not isOptional):
			message = "parameter '" + paramName + "' missing in oauth feature section of gadget spec";
			from src.gadgets.servlet import GadgetException;
			raise GadgetException, message;
		
		return None if (param == None) else param.strip();

class GadgetInfo:
	def __init__(self):
		self.__serviceName_;

		self.__providerInfo_;

	def getServiceName(self):
		return self.__serviceName_;

	def setServiceName(self, serviceName):
		self.__serviceName_ = serviceName;

	def getProviderInfo(self):
		return self.__providerInfo_;

	def setProviderInfo(self, providerInfo):
		self.__providerInfo_ = providerInfo;

class OAuthNoDataException(Exception):
	pass;

class BasicOAuthStore(OAuthStore):
	
	
	def __init__(self, consumerKey = None, privateKey = None):
		self.__consumerInfos_ = {};
		self.__tokens_ = {};
		self.__defaultConsumerKey_ = consumerKey;
		self.__defaultConsumerSecret_ = privateKey;

	def setHashMapsForTesting(self, consumerInfos, tokens):
		self.__consumerInfos_ = consumerInfos;
		self.__tokens_ = tokens;

	def getOAuthAccessorTokenKey(self, tokenKey, provInfo):
		provKey = ProviderKey();
		provKey.setGadgetUri(tokenKey.getGadgetUri());
		provKey.setServiceName(tokenKey.getServiceName());
		# AccesorInfo
		result = self.getOAuthAccessorProviderKey(provKey, provInfo);
		# TokenInfo
		accessToken = self.getTokenInfo(tokenKey);
		if (accessToken != None):
			# maybe convert into methods
			result.getAccessor().accessToken = accessToken.getAccessToken();
			result.getAccessor().tokenSecret = accessToken.getTokenSecret();
		
		return result;

	def getOAuthAccessorProviderKey(self, providerKey, provInfo):
		if (provInfo == None):
			raise OAuthNoDataException, "must pass non-None provider info to getOAuthAccessor";

		# AccesorInfo
		result = AccesorInfo();
		result.setHttpMethod(provInfo.getHttpMethod());
		result.setParamLocation(provInfo.getParamLocation());
		# ConsumerKeyAndSecret
		import md5;
		key = md5.new(serialize(providerKey)).hexdigest();
		consumerKeyAndSecret = None;
		if (self.__consumerInfos_.has_key(key)):
			consumerKeyAndSecret = self.__consumerInfos_[key];
		else:
			raise OAuthNoDataException, "The Key was invalid for consumerInfos, maybe your oauth.json configuration is wrong.";
		
		if (consumerKeyAndSecret == None):
			if (self.__defaultConsumerKey_ == None or self.__defaultConsumerSecret_ == None):
				raise OAuthNoDataException("ConsumerKeyAndSecret was None in oauth store");
			else:
				consumerKeyAndSecret = ConsumerKeyAndSecret(self.__defaultConsumerKey_, self.__defaultConsumerSecret_, OAuthStoreVars.KeyType['RSA_PRIVATE']);

		# OAuthServiceProvider
		oauthProvider = provInfo.getProvider();
		if (oauthProvider== None):
			raise OAuthNoDataException, "OAuthService provider was None in provider info";
		
		# Accesing the class
		usePublicKeyCrypto = (consumerKeyAndSecret.getKeyType() == OAuthStoreVars.KeyType['RSA_PRIVATE']);
		# OAuthConsumer
		
		if (usePublicKeyCrypto):
			consumer = OAuthConsumer(consumerKeyAndSecret.getConsumerKey(), None, oauthProvider);
		else: 
			consumer = OAuthConsumer(consumerKeyAndSecret.getConsumerKey(), consumerKeyAndSecret.getConsumerSecret(), oauthProvider);

		if (usePublicKeyCrypto):
			consumer.setProperty(OAuthSignatureMethod_RSA_SHA1.PRIVATE_KEY, consumerKeyAndSecret.getConsumerSecret());
			result.setSignatureType(OAuthStoreVars.SignatureType['RSA_SHA1']);
		else:
			result.setSignatureType(OAuthStoreVars.SignatureType['HMAC_SHA1']);
		
		result.setAccessor(OAuthAccessor(consumer));
		return result;

	def setOAuthConsumerKeyAndSecret(self, providerKey, keyAndSecret):
		import md5
		key = md5.new(serialize(providerKey)).hexdigest();

		self.__consumerInfos_[key] = keyAndSecret;

	def setTokenAndSecret(self, tokenKey, tokenInfo):
		import md5
		key = md5.new(serialize(tokenKey)).hexdigest();
		self.__tokens_[key] = tokenInfo;

	def __getTokenInfo(self, tokenKey):
		import md5
		key = md5.new(serialize(tokenKey)).hexdigest();
		
		return self.__tokens_[key] if self.__tokens_.has_key(key) else None;

class BasicGadgetOAuthTokenStore(GadgetOAuthTokenStore):
	
	
	def __init__(self, store, fetcher):
		#default location for consumer keys and secrets
		self.__OAUTH_CONFIG_ = "../config/oauth.json";
		self.__CONSUMER_SECRET_KEY_ = "consumer_secret";
		self.__CONSUMER_KEY_KEY_ = "consumer_key";
		self.__KEY_TYPE_KEY_ = "key_type";
		parent.__init__(store, fetcher);

	def initFromConfigFile(self, fetcher):
		# Read our consumer keys and secrets from config/oauth.js
		# This actually involves fetching gadget specs
		try:
			fp = open(self.__OAUTH_CONFIG_, 'r');
			oauthConfigStr = fp.read();
			fp.close();

			# remove all comments because this confuses the json parser
			# note: the json parser also crashes on trailing ,'s in records so please don't use them

			#contents = preg_replace('@/\\*(?:.|[\\n\\r])*?\\*/@', '', oauthConfigStr);
			import re;
			pattern = re.compile('@/\\*(?:.|[\\n\\r])*?\\*/@');
			contents = pattenr.sub('', oauthConfigStr);

			oauthConfig = Util.json_decode(contents, True);
			if (oauthConfig == contents):
				from src.gadgets.servlet import GadgetException;
				raise GadgetException, "OAuth configuration json failed to parse.";
			
			for gadgetUri in oauthConfig.keys():
				value = oauthConfig[gadgetUri];
				self.storeConsumerInfos(gadgetUri, value);

		except:
			from src.gadgets.servlet import GadgetException;
			raise GadgetException, e.value;

	def __storeConsumerInfos_(self, gadgetUri, oauthConfig):
		for key in oauthConfig.keys(): 
			value = oauthConfig[key];
			serviceName = key;
			consumerInfo = value;
			self.storeConsumerInfo(gadgetUri, serviceName, consumerInfo);

	def __storeConsumerInfo(self, gadgetUri, serviceName, consumerInfo):
		if (not consumerInfo.has_key(self.CONSUMER_SECRET_KEY) or not consumerInfo.has_key(self.CONSUMER_KEY_KEY) or not consumerInfo.has_key(self.KEY_TYPE_KEY)):
			raise Exception, "Invalid configuration in oauth.json";
		
		consumerSecret = consumerInfo[self.CONSUMER_SECRET_KEY];
		consumerKey = consumerInfo[self.CONSUMER_KEY_KEY];
		keyTypeStr = consumerInfo[self.KEY_TYPE_KEY];
		keyType = 'HMAC_SYMMETRIC';
		if (keyTypeStr == "RSA_PRIVATE"):
			keyType = 'RSA_PRIVATE';
			cache = Config.get('data_cache');
			cache = cache();

			import md5;

			cachedRequest = cache.get(md5.new("RSA_KEY_" + serviceName).hexdigest());

			if (cachedRequest != False):
				consumerSecret = cachedRequest;
			else:
				key = consumerInfo[self.CONSUMER_SECRET_KEY];
				if (len(key) == 0):
					raise Exception, "Invalid key";
				
				if (key.find("-----BEGIN") == -1):
					strip_this = [" ", "\n", "\r"];
					# removes breaklines and trim.
					rsa_private_key = str_replace(strip_this, "", key).strip();
					consumerSecret = OAuth.BEGIN_PRIVATE_KEY + "\n";
					chunks = str_split(rsa_private_key, 64);
					for chunk in chunks:
						consumerSecret = consumerSecret + chunk + "\n";
					
					consumerSecret = consumerSecret + OAuth.END_PRIVATE_KEY;
				else:
					consumerSecret = key;
				
				cache.set(md5.new("RSA_KEY_" + serviceName).hexdigest(), consumerSecret);

		kas = ConsumerKeyAndSecret(consumerKey, consumerSecret, keyType);
		self.storeConsumerKeyAndSecret(gadgetUri, serviceName, kas);
